﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Microsoft.Phone.Controls;
using Microsoft.Phone.Controls.Primitives;
using System.Collections.ObjectModel;
using Microsoft.Phone.Controls.Maps;
using System.Device.Location;
using Microsoft.Phone.Controls.Maps.Platform;
using Microsoft.Phone.Shell;
using System.Globalization;
using System.Threading;
using System.Windows.Media.Imaging;
using Microsoft.Phone.Tasks;

namespace SaveFuel
{
    public partial class MainPage : PhoneApplicationPage
    {
        private List<Supply> Supplies = null;
        //List<Coordinate> lastCoords = null;
        private GeoCoordinateWatcher watcher;
        //private Coordinate coords;
        private List<Pushpin> Pushpins = new List<Pushpin>();
        //private List<Coordinate> Coordinate = new List<Coordinate>();
        private string initialDistanceValue = "0";

        private double price = 0;
        private double money = 0;
        private double gasolina;

        private string supplyCoord = string.Empty;

        private string emptyVolumeCharacter = "-";
        private string currencySeparator = string.Empty;
        private bool isGpsSuccessfullyAcquired = true;
        private bool isFirstUsage = false;

        // Costruttore
        public MainPage()
        {
            InitializeComponent();
            Application.Current.Host.Settings.EnableFrameRateCounter = false;

            this.currencySeparator = App.cultureInfo.NumberFormat.CurrencyDecimalSeparator;

            #region InitBingMap

            bingMap.CredentialsProvider = new ApplicationIdCredentialsProvider("AsJaJpdbbJsNVTpBapTR51sI_uvWkHVDPYUHaiyuHtYSsW7GjhkGNTXSfstlIfs8");
            bingMap.LogoVisibility = Visibility.Collapsed;
            bingMap.CopyrightVisibility = Visibility.Collapsed;
            bingMap.Mode = new Microsoft.Phone.Controls.Maps.RoadMode();
            bingMap.Culture = App.cultureInfo;

            #endregion

            StartLocationService(GeoPositionAccuracy.High);

            this.Loaded += new RoutedEventHandler(MainPage_Loaded);
        }

        private void StartLocationService(GeoPositionAccuracy accuracy)
        {
            watcher = new GeoCoordinateWatcher(accuracy);
            watcher.MovementThreshold = 50;
            // Subscribe to the device's status changed event
            watcher.StatusChanged += new EventHandler<GeoPositionStatusChangedEventArgs>(watcher_StatusChanged);
            // Subscribe to the device's position changed event to receive GPS coordinates (longitude and latitude)
            watcher.PositionChanged += new EventHandler<GeoPositionChangedEventArgs<GeoCoordinate>>(watcher_PositionChanged);
        }

        void watcher_PositionChanged(object sender, GeoPositionChangedEventArgs<GeoCoordinate> e)
        {
            try
            {
                Deployment.Current.Dispatcher.BeginInvoke(() => MyPositionChanged(e));
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        /// <summary>
        /// Custom method called from the PositionChanged event handler
        /// </summary>
        /// <param name="e"></param>
        void MyPositionChanged(GeoPositionChangedEventArgs<GeoCoordinate> e)
        {
            App.currentLatitude = e.Position.Location.Latitude;
            App.currentLongitude = e.Position.Location.Longitude;
            StatusTextBlock.Text = String.Format(LastPositioneRetrieved.Text + " {0} " + At.Text + " {1} ", e.Position.Timestamp.LocalDateTime.ToLongDateString(), e.Position.Timestamp.LocalDateTime.ToShortTimeString());
            //StatusTextBlock.Text = LastPositioneRetrieved.Text + " " + e.Position.Timestamp.LocalDateTime.ToLongDateString();
        }

        private Pushpin LoadPinImage(Pushpin pin)
        {
            try
            {
                ImageBrush image = new ImageBrush()
                {
                    ImageSource = new System.Windows.Media.Imaging.BitmapImage
                                      (new Uri("Images/benzina.png", UriKind.RelativeOrAbsolute))
                };

                //---draw an ellipse inside the pushpin and fill it with the image---
                pin.Content = new Ellipse()
                {
                    Fill = image,
                    StrokeThickness = 10,
                    Height = 24,
                    Width = 24
                };
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }

            return pin;
        }

        void watcher_StatusChanged(object sender, GeoPositionStatusChangedEventArgs e)
        {
            try
            {
                Deployment.Current.Dispatcher.BeginInvoke(() => MyStatusChanged(e));
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }

        }

        /// <summary>
        /// Custom method called from the StatusChanged event handler
        /// </summary>
        /// <param name="e"></param>
        void MyStatusChanged(GeoPositionStatusChangedEventArgs e)
        {
            switch (e.Status)
            {
                case GeoPositionStatus.Disabled:
                    // The location service is disabled or unsupported.
                    // Alert the user                    
                    StatusTextBlock.Text = GeoPositionStatus_Disable.Text;
                    break;
                case GeoPositionStatus.Initializing:
                    // The location service is initializing.
                    // Disable the Start Location button
                    StatusTextBlock.Text = GeoPositionStatus_Initializing.Text;
                    break;
                case GeoPositionStatus.NoData:
                    // The location service is working, but it cannot get location data
                    // Alert the user and enable the Stop Location button
                    StatusTextBlock.Text = GeoPositionStatus_NoData.Text;
                    break;
                case GeoPositionStatus.Ready:
                    // The location service is working and is receiving location data
                    // Show the current position and enable the Stop Location button
                    StatusTextBlock.Text = GeoPositionStatus_Ready.Text;
                    break;

            }
        }

        void MainPage_Loaded(object sender, RoutedEventArgs e)
        {
            try
            {
                StartService();

                LoadData();
                LoadDistanceDataOnStartUp();

                Calculate();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        private void StartService()
        {
            if (!App.isGPSEnabled) // Probabilmente son al primo lancio (TODO: salvare su AppSetting e non su DB)
            {
                if (!isFirstUsage)
                {
                    if (MessageBox.Show(GPSConfirmOfUsage.Text, Warning.Text, MessageBoxButton.OKCancel) == MessageBoxResult.OK)
                    {
                        using (GestioneDBContext context = new GestioneDBContext(GestioneDBContext.ConnectionString))
                        {
                            context.Settings.First().GPS = true;
                            context.SubmitChanges();
                            App.isGPSEnabled = true;
                            isFirstUsage = true;
                            //this.isGpsSuccessfullyAcquired = true;
                        }
                    }
                }

            }

            if (watcher.Status != GeoPositionStatus.Disabled) // Se lo stato non è disabilitato allora cerco di recuperare la posizione
            {
                if (watcher.Status != GeoPositionStatus.Ready) // Vuol dire che ancora devo recuperare la posizione
                {
                    if (!watcher.TryStart(true, TimeSpan.FromSeconds(3))) // se non è andato a buon fine il recupero dei dati anche se è stato abilitato il GPS all'interno dell'applicazione
                    {
                        MessageBox.Show(ErrorGPSLocalization.Text, Warning.Text, MessageBoxButton.OK);
                        this.isGpsSuccessfullyAcquired = false;
                    }
                }
            }
            else // Il GPS a livello di device è disabilitato per qualche motivo
            {
                MessageBox.Show(GPSDeviceDisabled.Text, Warning.Text, MessageBoxButton.OK);
                this.isGpsSuccessfullyAcquired = false;
            }

        }

        private void LoadDistanceDataOnStartUp()
        {
            try
            {
                if (this.Supplies.Count != 0)
                {
                    // la lista mi arriva già ordinata al contrario, per cui devo solo estrarre il valore del contachilometri
                    if (App.distance.Equals("")) // è la prima volta che entro
                    {
                        this.initialDistanceValue = this.Supplies.First().TotalDistance.ToString();
                    }
                    tbTotalDistance.Text = this.initialDistanceValue; // setto come partenza il valore del contachilometri impostato nell'ultimo rifornimento
                    App.distance = this.initialDistanceValue;
                }

            }
            catch (Exception)
            {
                MessageBox.Show(ErrorReadTotalDistance.Text);
            }
        }

        private void Calculate()
        {
            try
            {
                NumberFormatInfo numberFormat = App.cultureInfo.NumberFormat;
                this.price = Convert.ToDouble(tbPrice.Text);
                this.money = Convert.ToDouble(tbMoneySpent.Text);

                this.gasolina = this.money / this.price; //calculateLitres(price, money, 5);
                lbGasolina.Text = this.gasolina.ToString("N", numberFormat) + " " + App.volumeUnit; //VolumeMeasure.Text;
            }
            catch (Exception)
            {
                lbGasolina.Text = this.emptyVolumeCharacter;
            }
        }

        /// <summary>
        /// Responsabile di inizializzare i dati dell contachilometri all'avvio dell'applicazione
        /// </summary>
        private void LoadInterfaceData()
        {
            App.distance = this.initialDistanceValue;
        }

        private void LoadPushpin(GeoCoordinate coords)
        {
            try
            {
                Pushpin pin = new Pushpin();
                GeoCoordinate pinCoords = coords; //new GeoCoordinate(latitudeCoord, longituteCoord);
                pin.Location = pinCoords;
                pin = LoadPinImage(pin);
                // il tag mi vale come entry point della mappa
                pin.Tag = pinCoords;
                // add pin to map
                this.Pushpins.Add(pin);
                bingMap.Children.Add(pin);

                SetLocation(pin, 15);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }

        }

        /// <summary>
        /// Visualizza come punto sulla mappa l'ultimo luogo dove si è fatto rifornimento
        /// </summary>
        /// <param name="pin"></param>
        /// <param name="zoomLevel"></param>
        private void SetLocation(Pushpin pin, double zoomLevel)
        {
            bingMap.SetView(pin.Tag as GeoCoordinate, zoomLevel);
        }

        private void ResetForm()
        {
            try
            {
                //LoadInterfaceData();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        /// <summary>
        /// Responsabile di caricare tutti i dettagli dal database
        /// </summary>
        private void LoadData()
        {
            try
            {
                using (GestioneDBContext context = new GestioneDBContext(GestioneDBContext.ConnectionString))
                {
                    this.Supplies = context.Supplies.ToList();
                    this.Supplies.Reverse();

                    DetailsListBox.ItemsSource = this.Supplies;
                }
            }
            catch (Exception) // ex
            {
                MessageBox.Show(ErrorReadRefueling.Text);
            }
        }

        private GeoCoordinate splitCoordinateString(string fullCoordStr)
        {
            string[] splitCoord = fullCoordStr.Split(';');

            double lat = Convert.ToDouble(splitCoord[0]);
            double lng = Convert.ToDouble(splitCoord[1]);

            return new GeoCoordinate(lat, lng);
        }

        private void Save_Click(object sender, EventArgs e)
        {
            try
            {

                if (checkFormValue())
                {
                    #region CREAZIONE OGGETTO E INSERIMENTO

                    ((ApplicationBarIconButton)ApplicationBar.Buttons[0]).IsEnabled = false;
                    StatusTextBlock.Text = string.Empty;

                    #region CREAZIONE OGGETTO SUPPLY
                    // creo oggetto Supply
                    Supply supply = new Supply();

                    supply.SupplyId = Guid.NewGuid();
                    // Modifico il date time in base alla cultura                
                    DateTime dt = (DateTime)datePickerRefuelingDate.Value;
                    string dateString = dt.ToString("d");
                    supply.Data = DateTime.ParseExact(dateString, App.cultureInfo.DateTimeFormat.ShortDatePattern.ToString(), App.cultureInfo.DateTimeFormat);

                    supply.TotalDistance = Convert.ToInt32(tbTotalDistance.Text);
                    supply.DistanceUnit = App.distanceUnit;

                    supply.Price = this.price;
                    supply.PriceUnit = App.moneyUnit + "/" + App.volumeUnit;

                    supply.Money = this.money;
                    supply.MoneyUnit = App.moneyUnit;

                    supply.Gasolina = this.gasolina;
                    supply.GasolinaUnit = App.volumeUnit;


                    string fullFuelImagePath = string.Empty;

                    if (isFull.IsChecked == true)
                    {
                        fullFuelImagePath = "Images/fillUp_48x48.png";
                    }
                    else
                    {
                        fullFuelImagePath = "Images/noFillUp_48x48.png";
                    }

                    supply.FillUpImage = fullFuelImagePath;


                    #endregion

                    if (App.isGPSEnabled) // se il GPS è già stato abilitato dall'utente o lo ha appena abilitato
                    {
                        this.supplyCoord = App.currentLatitude.ToString() + ";" + App.currentLongitude.ToString();
                        supply.Coordinates = this.supplyCoord;

                        //SetGPSPositionToSupplyItem(supply);

                        string gpsOnImagePath = string.Empty;
                        if (this.isGpsSuccessfullyAcquired)
                        {
                            gpsOnImagePath = "Images/gps_on.png";
                        }
                        supply.GpsOn = gpsOnImagePath;
                    }


                    // Salva oggetto Supply su database
                    using (GestioneDBContext context = new GestioneDBContext(GestioneDBContext.ConnectionString))
                    {
                        context.Supplies.InsertOnSubmit(supply);
                        context.SubmitChanges();
                    }

                    //((ApplicationBarIconButton)ApplicationBar.Buttons[1]).IsEnabled = false;
                    MessageBox.Show(SuccessfullyInsert.Text);
                    ((ApplicationBarIconButton)ApplicationBar.Buttons[0]).IsEnabled = false;

                    LoadData();
                    ResetForm();

                    #endregion
                }
                else
                {
                    MessageBox.Show(ErrorMessage.Text);
                }
            }
            catch (Exception)
            {
                MessageBox.Show(FailedInsert.Text);
            }

        }

        private bool checkFormValue()
        {
            bool result = false;
            if (this.tbTotalDistance.Text != "0" && this.tbPrice.Text != string.Empty && this.tbMoneySpent.Text != string.Empty)
            {
                result = true;
            }
            return result;
        }

        private void DetailsListBox_Loaded(object sender, RoutedEventArgs e)
        {
            try
            {
                LoadData();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        private void tbTotalDistance_GotFocus(object sender, RoutedEventArgs e)
        {
            if (this.initialDistanceValue == string.Empty)
            {
                tbTotalDistance.Text = "0";
            }
        }

        private void LocalizeItem_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                var menuItemCoords = ((MenuItem)sender).CommandParameter;

                if (menuItemCoords != null)
                {
                    LoadPushpin(splitCoordinateString(menuItemCoords.ToString()));
                    ApplicationTitle.SelectedIndex = ApplicationTitle.Items.IndexOf(PivotItem3MainPage);
                }
                else
                {
                    MessageBox.Show(NoGPSCoordinatesRetrived.Text);
                }
            }
            catch (Exception)
            {
                MessageBox.Show(ErrorLocalization.Text);
            }

        }

        private void DeleteItem_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                var menuItemGuid = ((MenuItem)sender).CommandParameter;


                if (MessageBox.Show(DeleteRefuelMessage.Text, Warning.Text, MessageBoxButton.OKCancel) == MessageBoxResult.OK)
                {
                    using (GestioneDBContext context = new GestioneDBContext(GestioneDBContext.ConnectionString))
                    {
                        Supply supply = context.Supplies.Where(x => x.SupplyId.ToString() == menuItemGuid).SingleOrDefault();
                        context.Supplies.DeleteOnSubmit(supply);
                        context.SubmitChanges();
                    }
                }
                LoadData();
            }
            catch (Exception)
            {
                MessageBox.Show(ErrorDeletingRefuelMessage.Text);
            }

            //ListBoxItem contextMenuListItem = DetailsListBox.ItemContainerGenerator.ContainerFromItem((sender as ContextMenu).DataContext) as ListBoxItem;            
        }

        #region AppBar Functions
        private void Configuration_Click(object sender, EventArgs e)
        {
            NavigationService.Navigate(new Uri("/Configuration.xaml", UriKind.Relative));
        }

        private void Privacy_Click(object sender, EventArgs e)
        {
            NavigationService.Navigate(new Uri("/Privacy.xaml", UriKind.Relative));
        }

        private void Guide_Click(object sender, EventArgs e)
        {
            NavigationService.Navigate(new Uri("/Guide.xaml", UriKind.Relative));
        }
        #endregion

        #region Tap Method

        private void tbTotalDistance_Tap(object sender, System.Windows.Input.GestureEventArgs e)
        {
            if (((ApplicationBarIconButton)ApplicationBar.Buttons[0]).IsEnabled == false) // vuol dire che voglio inserire un nuovo rifornimento, per cui riabilito il bottone salva
            {
                ((ApplicationBarIconButton)ApplicationBar.Buttons[0]).IsEnabled = true;
            }
            NavigationService.Navigate(new Uri("/NumberSelector/TotalDistance.xaml", UriKind.Relative));
        }

        private void tbPrice_Tap(object sender, System.Windows.Input.GestureEventArgs e)
        {
            if (((ApplicationBarIconButton)ApplicationBar.Buttons[0]).IsEnabled == false) // vuol dire che voglio inserire un nuovo rifornimento, per cui riabilito il bottone salva
            {
                ((ApplicationBarIconButton)ApplicationBar.Buttons[0]).IsEnabled = true;
            }
            NavigationService.Navigate(new Uri("/NumberSelector/FuelPrice.xaml", UriKind.Relative));
        }

        private void tbMoneySpent_Tap(object sender, System.Windows.Input.GestureEventArgs e)
        {
            if (((ApplicationBarIconButton)ApplicationBar.Buttons[0]).IsEnabled == false) // vuol dire che voglio inserire un nuovo rifornimento, per cui riabilito il bottone salva
            {
                ((ApplicationBarIconButton)ApplicationBar.Buttons[0]).IsEnabled = true;
            }
            NavigationService.Navigate(new Uri("/NumberSelector/MoneySpent.xaml", UriKind.Relative));
        }

        #endregion

        #region Loaded Method

        private void tbTotalDistance_Loaded(object sender, RoutedEventArgs e)
        {
            if (App.distance != string.Empty)
            {
                tbTotalDistance.Text = Convert.ToInt32(App.distance).ToString();
                this.initialDistanceValue = tbTotalDistance.Text;
            }
            else
            {
                tbTotalDistance.Text = this.initialDistanceValue;
            }
        }

        private void tbPrice_Loaded(object sender, RoutedEventArgs e)
        {
            if (App.price != string.Empty)
            {
                tbPrice.Text = App.price;
            }
        }

        private void tbMoneySpent_Loaded(object sender, RoutedEventArgs e)
        {
            if (App.money != string.Empty)
            {
                string[] moneySpentArray = App.money.Split(Convert.ToChar(App.currencySeparator));
                string value = moneySpentArray[0];
                string decimals = moneySpentArray[1];

                tbMoneySpent.Text = Convert.ToInt32(value).ToString() + App.currencySeparator + decimals;
            }
        }

        #endregion

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            WebBrowserTask wtb = new WebBrowserTask();
            wtb.Uri = new Uri("http://aaccostatech.wordpress.com/", UriKind.Absolute);
            wtb.Show();  
        }
    }

}